from logging import getLogger

import zope.interface
from zope.component import getGlobalSiteManager

from meercat.interfaces import IMetadata
from meercat.base.metadata import Metadata
from meercat.mapreduce import interfaces
from meercat.mapreduce.registry import GlobalMapperRegistry
from meercat.mapreduce.exceptions import MapperError, NoPath, UnkownFormat



log = getLogger('meercat.mapreduce.inline')

def mapreduce(input, targetFormat, mapperRegistry=GlobalMapperRegistry,
              componentRegistry=None, pathErrors=False, mappingErrors=True):
    if componentRegistry is None:
        componentRegistry = getGlobalSiteManager()
    
    mapperRegistry = interfaces.IMapperRegistry(mapperRegistry)
    
    reducer = componentRegistry.getUtility(interfaces.IReducer, targetFormat)
    
    mapped = []
    log.debug('reducer: %s' % (str(reducer)))
    for i in input:
        i = IMetadata(i)
        
        try:
            mapped.append(mapperRegistry.getMapper(i.getFormat(),
                                                   targetFormat).map(i))
        except (NoPath, UnkownFormat), e:
            if pathErrors:
                log.error('Path error: %s' % (str(e)))
                raise e
            else:
                log.debug('Path error: %s' % (str(e)))
        except Exception, e:
            if mappingErrors:
                o = log.error
            else:
                o = log.warning
                
            o('Mapping error: %s' % (str(e)))
            import sys, traceback
            for line in traceback.format_exception(*sys.exc_info()):
                o(line)
            if mappingErrors:
                raise e
    
    log.debug('metadata mapped...')
    mapped = filter(lambda m: m is not None, mapped)
    
    if len(mapped) > 0:
        log.debug('Reducing mapped metadata')
        return reducer.reduce(*mapped)
    log.debug('No mapped metadata to reduce')
    return None
    